package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.cloudfun.campuscontract.RemoteDeviceInvokeHistoryChainService;
import com.cloudfun.campuscontract.dto.DeviceInvokeHistoryDTO;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.constant.LoanStatus;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.vo.InvokeHistoryFiAdminExportVO;
import com.cloudfun.campusshare.common.model.vo.InvokeHistoryMerchantExportVO;
import com.cloudfun.campusshare.common.model.vo.InvokeHistoryVO;
import com.cloudfun.campusshare.common.response.PageResult;
import com.cloudfun.campusshare.common.security.AuthenticationHolder;
import com.cloudfun.campusshare.dao.InvokeHistoryDao;
import com.cloudfun.campusshare.entity.*;
import com.cloudfun.campusshare.repo.InvokeHistoryEntityRepo;
import com.cloudfun.campusshare.repo.LoanEntityRepo;
import com.cloudfun.campusshare.repo.UserEntityRepo;
import com.cloudfun.campusshare.service.DeviceService;
import com.cloudfun.campusshare.service.InvokeHistoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by Huqin on 2019/12/11
 */
@Service
@Slf4j
public class InvokeHistoryServiceImpl implements InvokeHistoryService {

    @Autowired
    private InvokeHistoryEntityRepo invokeHistoryEntityRepo;

    @Autowired
    private InvokeHistoryDao invokeHistoryDao;

    @Autowired
    private UserEntityRepo userEntityRepo;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private LoanEntityRepo loanEntityRepo;

    @Reference(timeout = 10_000)
    private RemoteDeviceInvokeHistoryChainService remoteDeviceInvokeHistoryChainService;

    @Autowired
    private TaskExecutor taskExecutor;// spring async 默认的任务执行器

    private static final Map<String, String> functionNameMap = new HashMap<>();

    static {
        functionNameMap.put("getPropertyByName", "查询属性");
        functionNameMap.put("getCautionList", "查询告警");
        functionNameMap.put("wash", "洗涤");
        functionNameMap.put("dry", "烘干");
        functionNameMap.put("pulseWash", "波轮洗涤");
        functionNameMap.put("shoeWash", "洗鞋");
        functionNameMap.put("reset", "重置");
        functionNameMap.put("isOnline", "查询是否在线");
    }

    @Override
    public void create(InvokeHistoryEntity invokeHistoryEntity) {
        log.debug("保存请求历史：{}", invokeHistoryEntity);
        if (invokeHistoryEntity.getMethod().equals("operate")) {
            taskExecutor.execute(() -> {
                // 异步设备调用历史记录上链
                DeviceInvokeHistoryDTO deviceInvokeHistoryDTO = new DeviceInvokeHistoryDTO();
                BeanUtil.copyProperties(invokeHistoryEntity, deviceInvokeHistoryDTO);
                remoteDeviceInvokeHistoryChainService.addInvokeHistory(deviceInvokeHistoryDTO);
            });
        }
        invokeHistoryEntityRepo.save(invokeHistoryEntity);
    }

    @Override
    public PageResult<InvokeHistoryVO> search(String id, Pageable pageable) {
        PageResult<InvokeHistoryVO> pageResult = invokeHistoryDao.search(id, pageable);
        List<InvokeHistoryVO> elements = pageResult.getElements();
        // 设置username
        List<String> userIdList = elements.stream().map(InvokeHistoryVO::getUserId).collect(Collectors.toList());
        Iterable<UserEntity> userEntities = userEntityRepo.findAllById(userIdList);
        Map<String, String> userIdUsernameMap = new HashMap<>();
        userEntities.forEach(userEntity -> {
            userIdUsernameMap.put(userEntity.getId(), userEntity.getUsername());
        });
        elements.forEach(invokeHistoryVO -> {
            invokeHistoryVO.setFunction(functionNameMap.get(invokeHistoryVO.getFunction()));
            invokeHistoryVO.setUsername(userIdUsernameMap.get(invokeHistoryVO.getUserId()));
        });
        return pageResult;
    }

    @Override
    public List<InvokeHistoryMerchantExportVO> merchantExportDeviceInvokeHistory(String imei) {
        DeviceEntity device = deviceService.getDeviceWithAuthByImei(imei);
        List<InvokeHistoryEntity> invokeHistoryEntities = invokeHistoryEntityRepo.findAllByDeviceIdOrderByCreateTime(device.getId());
        if (CollectionUtils.isEmpty(invokeHistoryEntities)) {
            return new ArrayList<>();
        }
        Set<String> userIdSet = invokeHistoryEntities.stream().map(InvokeHistoryEntity::getUserId).collect(Collectors.toSet());
        List<UserEntity> userEntities = userEntityRepo.findByIdIn(userIdSet);
        Map<String, String> userIdNameMap = userEntities.stream().collect(Collectors.toMap(UserEntity::getId, UserEntity::getUsername));

        return invokeHistoryEntities.stream().map(invokeHistoryEntity -> {
            InvokeHistoryMerchantExportVO invokeHistoryMerchantExportVO = new InvokeHistoryMerchantExportVO();
            BeanUtils.copyProperties(invokeHistoryEntity, invokeHistoryMerchantExportVO);
            if (null != invokeHistoryEntity.getCreateTime()) {
                invokeHistoryMerchantExportVO.setCreateTime(new Date(Long.parseLong(invokeHistoryEntity.getCreateTime())));
            }
            invokeHistoryMerchantExportVO.setFunction(functionNameMap.get(invokeHistoryEntity.getFunction()));
            invokeHistoryMerchantExportVO.setUsername(userIdNameMap.get(invokeHistoryEntity.getUserId()));
            return invokeHistoryMerchantExportVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<InvokeHistoryFiAdminExportVO> fiOrAdminExportDeviceInvokeHistory(String imei) {
        DeviceEntity deviceEntity = deviceService.getDeviceWithoutAuthByImei(imei);
        if (!AuthenticationHolder.isAdmin()) {
            ProjectEntity project = deviceEntity.getProject();
            if (null == project) {
                throw new BusinessException(Code.NODATA);
            }
            LoanEntity loanEntity = loanEntityRepo.findById(project.getLoanId()).orElseThrow(() -> new BusinessException(Code.NODATA));
            if (loanEntity.getStatus().equals(LoanStatus.CREATING) || !loanEntity.getLenderId().equals(AuthenticationHolder.getUserId())) {
                throw new BusinessException(Code.PERMISSION_DENIED);
            }
        }
        List<InvokeHistoryEntity> invokeHistoryEntities = invokeHistoryEntityRepo.findAllByDeviceIdOrderByCreateTime(deviceEntity.getId());
        if (CollectionUtils.isEmpty(invokeHistoryEntities)) {
            return new ArrayList<>();
        }

        return invokeHistoryEntities.stream().map(invokeHistoryEntity -> {
            InvokeHistoryFiAdminExportVO invokeHistoryFiAdminExportVO = new InvokeHistoryFiAdminExportVO();
            BeanUtils.copyProperties(invokeHistoryEntity, invokeHistoryFiAdminExportVO);
            if (null != invokeHistoryEntity.getCreateTime()) {
                invokeHistoryFiAdminExportVO.setCreateTime(new Date(Long.parseLong(invokeHistoryEntity.getCreateTime())));
            }
            invokeHistoryFiAdminExportVO.setFunction(functionNameMap.get(invokeHistoryEntity.getFunction()));
            return invokeHistoryFiAdminExportVO;
        }).collect(Collectors.toList());
    }
}
